#include "StdAfx.h"
#include <stdlib.h>
#include <glut.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>                                  
#include <GlAux.h>
#include <SOIL.h>

using namespace std;

// prototypes

void loadFile(char*);
void baumDisplay(void);
void init(void);
void initlight(void);
void JunakMariusDisplay(void);
void loadObjects(void);
void loadFile( char*);
void displayBaum(void);

GLuint list;							
GLuint texture[1];	

struct triangle{
	int a;
	int b;
	int c;
};
struct vertice{
	float v[3];
};
struct normal{
	float v[3];
};
vertice calcNorm(vertice a, vertice b, vertice c){
	vertice ret;
	vertice v1,v2;
	v1.v[0] = b.v[0] - a.v[0]; 
	v1.v[1] = b.v[1] - a.v[1]; 
	v1.v[2] = b.v[2] - a.v[2];

	v2.v[0] = c.v[0] - a.v[0]; 
	v2.v[1] = c.v[1] - a.v[1]; 
	v2.v[2] = c.v[2] - a.v[2];

	ret.v[0] = v1.v[1] * v2.v[2] - v1.v[2] * v2.v[1]; 
	ret.v[1] = v1.v[2] * v2.v[0] - v1.v[0] * v2.v[2]; 
	ret.v[2] = v1.v[0] * v2.v[1] - v1.v[1] * v2.v[0]; 

	return ret;
}
void JunakMariusDisplay(){
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; 
	glMaterialfv(GL_FRONT, GL_AMBIENT, white); 
	glMaterialfv(GL_FRONT, GL_DIFFUSE, white); 
	glMaterialfv(GL_FRONT, GL_SPECULAR, white); 
	glMaterialf(GL_FRONT, GL_SHININESS, 128.0);  

	//obj1
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	gluLookAt(0.0, 4.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glTranslatef(8,0,0);
	glCallList(list);



	//chess
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	gluLookAt(0.0, 4.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);	
	glTranslatef(0,6,0);
	glBegin(GL_TRIANGLES);                     
	glNormal3f(0,0,1);
	glTexCoord2f(0,0);
	glVertex3f( 0.0f, 0.0f, 0.0f);              // bottomleft
	glTexCoord2f(1,0);
	glVertex3f(1.0f,0.0f, 0.0f);              // bottomright
	glTexCoord2f(1,1);
	glVertex3f( 1.0f,1.0f, 0.0f);              // topright

	glNormal3f(0,0,1);
	glTexCoord2f(1,1);
	glVertex3f( 1.0f, 1.0f, 0.0f);             // topright
	glTexCoord2f(0,1);
	glVertex3f(0.0f,1.0f, 0.0f);              // topleft
	glTexCoord2f(0,0);
	glVertex3f( 0.0f,0.0f, 0.0f);              // bottomleft
	glEnd();   


	glDisable(GL_TEXTURE_2D); 
	displayBaum();

	//obj2
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	gluLookAt(0.0, 4.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glTranslatef(-8,0,0);
	glCallList(list+1);

	glFlush();
}
void displayBaum(){
	//Tree
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	gluLookAt(0.0, 4.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glRotatef(0,0,1,0);
	glScalef(1,4,1);
	glTranslatef(0,0,0);
	glutSolidCube(1.0);

	//branch1
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	gluLookAt(0.0, 4.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glRotatef(0,0,1,0);
	glTranslatef(-1.5, 2.5, 0);
	glRotatef(60,0,0,1);
	glScalef(1,4,1);
	glutSolidCube(1.0);

	//branch2
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	gluLookAt(0.0, 4.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glRotatef(0+120,0,1,0);
	glTranslatef(-1.5, 2.5, 0);
	glRotatef(60,0,0,1);
	glScalef(1,4,1);
	glutSolidCube(1.0);

	//branch3
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	gluLookAt(0.0, 4.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glRotatef(0+240,0,1,0);
	glTranslatef(-1.5, 2.5, 0);
	glRotatef(60,0,0,1);
	glScalef(1,4,1);
	glutSolidCube(1.0);

}
void loadFile( char* filename )
{
	int normalsIncluded = 0;
	vector<normal> normals;
	vector<vertice> vertices;
	vector<triangle> triangles;
	string line; 
	triangle t;
	vertice v;
	normal n;
	int a,b,c;
	int x = 0;

	ifstream file( filename );

	if (!file)
		exit( 1 );

	while ( getline( file, line) )
	{

		cout << line << endl;

		if (sscanf(line.c_str(),"v %f %f %f",&(v.v[0]),&(v.v[1]),&(v.v[2])))
		{
			vertices.push_back( v );
			printf( "valid: v %f %f %f\n", v.v[0], v.v[1], v.v[2] );
		}
		if (sscanf(line.c_str(),"vn %f %f %f",&(n.v[0]),&(n.v[1]),&(n.v[2])))
		{
			normalsIncluded = 1;
			normals.push_back( n );
			printf( "valid: vn %f %f %f\n", v.v[0], v.v[1], v.v[2] );
		}

		if (sscanf( line.c_str(), "f %i %i %i", &t.a, &t.b, &t.c ) == 4)
		{
			t.a--; t.b--; t.c--;

			triangles.push_back( t );
			printf( "valid: f %i %i %i\n", t.a,t.b,t.c );
		}
		if (sscanf( line.c_str(), "f %i//%i %i//%i %i//%i", &t.a, &a, &t.b, &b, &t.c ,&c) ) //second ints are normalindices but we ignore them. Because in our examples they are equal to verticeindecies
		{
			t.a--; t.b--; t.c--;

			triangles.push_back( t );
			printf( "valid:f %i//%i %i//%i %i//%i \n", &t.a, &a, &t.b, &b, &t.c ,&c);
		}
	}

	glBegin( GL_TRIANGLES);
	for each (triangle tri in triangles){
		x++;
		x = x%2;
		if(normalsIncluded == 0){
			vertice norm;
			norm = calcNorm(vertices[tri.a], vertices[tri.b], vertices[tri.c]);
			if(x==0)
				glTexCoord2f(1,0);
			else
				glTexCoord2f(1,0);
			glNormal3f(norm.v[0],norm.v[1],norm.v[2]);
		}
		if(normalsIncluded){
			if(x==0)
				glTexCoord2f(1,0);
			else
				glTexCoord2f(1,0);
			glNormal3f(normals[tri.a].v[0],normals[tri.a].v[1], normals[tri.a].v[2]);
		}
		glVertex3f( vertices[tri.a].v[0], vertices[tri.a].v[1], vertices[tri.a].v[2] );

		if(normalsIncluded){
			glNormal3f(normals[tri.b].v[0],normals[tri.b].v[1], normals[tri.b].v[2]);
		}
		if(x==0)
			glTexCoord2f(0,1);
		else
			glTexCoord2f(1,1);
		glVertex3f( vertices[tri.b].v[0], vertices[tri.b].v[1], vertices[tri.b].v[2] );

		if(normalsIncluded){
			glNormal3f(normals[tri.c].v[0],normals[tri.c].v[1], normals[tri.c].v[2]);
		}
		if(x==0)
			glTexCoord2f(0,0);
		else
			glTexCoord2f(0,1);
		glVertex3f( vertices[tri.c].v[0], vertices[tri.c].v[1], vertices[tri.c].v[2] );


		printf( "valid: f %i %i %i\n", t.a,t.b,t.c );
		printf( "valid: v %f %f %f\n", vertices[t.a].v[0],vertices[t.a].v[1],vertices[t.a].v[2]);

		printf( "valid: v %f %f %f\n", vertices[t.b].v[0],vertices[t.b].v[1],vertices[t.b].v[2]);

		printf( "valid: v %f %f %f\n", vertices[t.c].v[0],vertices[t.c].v[1],vertices[t.c].v[2]);

	}
	glEnd();
	return;
}
/**
* function by nehe.gamedev.net (lesson6)
*/
int loadGLTextures()                                    // Load Bitmaps And Convert To Textures
{
	// load an image file directly as a new OpenGL texture 
	texture[0] = SOIL_load_OGL_texture
		(
		"schach.bmp",
		SOIL_LOAD_AUTO,
		SOIL_CREATE_NEW_ID,
		SOIL_FLAG_INVERT_Y
		);

	if(texture[0] == 0)
		return false;
	// Typical Texture Generation Using Data From The Bitmap
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

	return true;                                        // Return Success
}
void loadObjects(){
	list = glGenLists(2);
	glNewList(  list, GL_COMPILE );   
	loadFile( "cube.obj");
	glEndList();
	glNewList(  list+1, GL_COMPILE );   
	loadFile( "cow-nonormals.obj");
	glEndList();
}
void init(){
	glEnable(GL_TEXTURE_2D); // new
	glClearColor (0.0, 0.0, 0.0, 0.0);
	glShadeModel (GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_NORMALIZE); 
	glEnable(GL_COLOR_MATERIAL);
}
void reshape (int w, int h)
{
	glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 30.0);
	glMatrixMode (GL_MODELVIEW);
}
void idle(){}
void keyboard(unsigned char key, int x, int y)
{
	switch (key) {
	case 27:
		exit(1);
		break;
	}
}
void initlight(void){
	glLoadIdentity();

	GLfloat spotlight_ambient[] = { 0.0, 0.0, 0.0, 0.3 };
	GLfloat spotlight_diffuse[] = {0, 0.7, 0.0, 0.5};
	GLfloat spotlight_specular[] = {0, 0.7, 0.0, 0.5};

	GLfloat pointlight_ambient[] = { 0.0, 0.0, 0.0, 0.3 };
	GLfloat pointlight_diffuse[] = {0.4, 0.0, 0.0, 0.3};
	GLfloat pointlight_specular[] = {0.4, 0.0, 0.0, 0.3};

	GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 0.3 };
	GLfloat light_diffuse[] = {0.0, 0.0, 0.4, 0.4};
	GLfloat light_specular[] = {0.0, 0.0, 0.4, 0.4};
	GLfloat light_direction[] = {1.0, -1.0, 0.0, 0.0}; 

	GLfloat pointlight_position[] = {0.0, 10.0, 0.0, 1.0}; 

	GLfloat spotlight_position[] = {-8, 0, 10, 1};
	GLfloat spotlight_direction[] = {0.0, 0.0, -1.0}; 

	//light
	glLightfv(GL_LIGHT0, GL_POSITION, light_direction);
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

	//pointlight
	glLightfv(GL_LIGHT1, GL_POSITION, pointlight_position);
	glLightfv(GL_LIGHT1, GL_AMBIENT, pointlight_ambient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, pointlight_diffuse);
	glLightfv(GL_LIGHT1, GL_SPECULAR, pointlight_specular);

	//spotlight 
	glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION,	spotlight_direction);
	glLightfv(GL_LIGHT2, GL_POSITION, spotlight_position);
	glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 35);
	glLightf(GL_LIGHT2, GL_SPOT_EXPONENT, 4);
	glLightfv(GL_LIGHT2, GL_AMBIENT, spotlight_ambient);
	glLightfv(GL_LIGHT2, GL_DIFFUSE, spotlight_diffuse);
	glLightfv(GL_LIGHT2, GL_SPECULAR, spotlight_specular);


	glEnable(GL_LIGHT2);
	glEnable(GL_LIGHT1);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);	
}
int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize (1024, 768); 
	glutInitWindowPosition (100, 100);
	glutCreateWindow (argv[0]);
	init ();
	initlight();
	loadGLTextures();
	loadObjects();
	glutDisplayFunc(JunakMariusDisplay); 
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutIdleFunc( idle );
	glutMainLoop();
}